R Configuration

Below we display our sessionInfo().

sessionInfo(package=NULL)
R version 3.4.0 (2017-04-21)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Sierra 10.12.4

Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.4/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] readr_1.1.0           readxl_1.0.0          reshape2_1.4.2        choroplethrMaps_1.0.1
 [5] choroplethr_2.2.0     acs_2.0               XML_3.98-1.6          plyr_1.8.4           
 [9] stringr_1.2.0         RColorBrewer_1.1-2    gridExtra_2.2.1       data.world_0.1.2     
[13] dplyr_0.5.0           ggplot2_2.2.1         DT_0.2                shinydashboard_0.5.3 
[17] shiny_1.0.3          

loaded via a namespace (and not attached):
 [1] splines_3.4.0       lattice_0.20-35     WDI_2.4             colorspace_1.3-2    htmltools_0.3.6    
 [6] yaml_2.1.14         base64enc_0.1-3     survival_2.41-3     foreign_0.8-68      DBI_0.6-1          
[11] cellranger_1.1.0    munsell_0.4.3       gtable_0.2.0        htmlwidgets_0.8     evaluate_0.10      
[16] latticeExtra_0.6-28 knitr_1.15.1        httpuv_1.3.3        curl_2.5            htmlTable_1.9      
[21] Rcpp_0.12.10        acepack_1.4.1       xtable_1.8-2        scales_0.4.1        backports_1.0.5    
[26] checkmate_1.8.2     Hmisc_4.0-2         jsonlite_1.4        mime_0.5            hms_0.3            
[31] digest_0.6.12       stringi_1.1.5       rprojroot_1.2       tools_3.4.0         bitops_1.0-6       
[36] magrittr_1.5        lazyeval_0.2.0      RCurl_1.95-4.8      tibble_1.3.0        Formula_1.2-1      
[41] cluster_2.0.6       Matrix_1.2-10       rsconnect_0.7       data.table_1.10.4   httr_1.2.1         
[46] assertthat_0.2.0    rmarkdown_1.4       R6_2.2.0            rpart_4.1-11        nnet_7.3-12        
[51] compiler_3.4.0     

Our Datasets

The first dataset was created by students at Georgia Tech University. It focuses on the demographics of test-takers for the AP CS test administered by the Collegeboard in 2013. The lowest score for an AP test is a 1, while the highest score is a 5. The second dataset that we used to join the AP dataset contains census data related to income in the U.S in 2015. Download AP dataset here. Download the 2015 US Census Income data US Census population estimates, Income (American Community Survey, 2011-2015)

AP Test Dataset Columns

Measure Description
2013 data The U.S. States
# schools Number of school that offer AP CS tests
Total # Number of AP CS test takers
Yield per teacher Number of student test takers per teacher
# passed The number of test takers who scored 3 out of 5 or above
% passed The percentage of passed test takers over the total number of test takers
# female The number of female test taker
# female passed The number of female test taker who scored 3 out of 5 or above
% female passed The percentage of passed female test takers over the total number of female test takers
% female The percentage of female test takers over the total number of test takers
# Black The number of black test taker
# Black Passed The number of black test taker who scored 3 out of 5 or above
% Black passed The percentage of passed black test takers over the total number of test takers
% black in state Percentage of black in state
# Hispanic The number of Hispanic test taker
# Hispanic passed The number of Hispanic test taker who scored 3 out of 5 or above
% Hispanic passed The percentage of passed Hispanic test takers over the total number of test takers
% Hispanic in state Percentage of Hispanics in state
% taking / % state * 100 Attempt rate of Hispanic test takers

Census Dataset Columns

Measure Description
State State abbreviation
AreaName State full name
median_household_income Median household income in 2015
per_capita_income A measurement an area’s average income
gini_index A measurement of inequality. (0 stands for perfect equality)

Methodology

Original Dataset

The 2013 AP CS test dataset before the cleaning process

ETL Logic

  1. As seen from the previous table, the uncleaned AP CS data is filled up with empty columns, asterisks and multiple columns that we will not use in our data visualization. We followed the following process to clean up the data:
   i. Build an ETL script to pull the data from data.world and proceed the cleaning process 
### Load Required Packages
require(readxl)
# Set the working directory to access CSVs
setwd("~/s17dvfinalproject-dvproject-4-chou-zeng-zhang-zhang/01 Data")

# df <- read_excel("./01 Data/DetailedStateInfoAP-CS-A-2006-2013-with-PercentBlackAndHIspanicByState-fixed.xlsx", sheet = "Sheet2")
df <- read_excel("../01 Data/DetailedStateInfoAP-CS-A-2006-2013-with-PercentBlackAndHIspanicByState-fixed.xlsx", sheet = "Sheet2")
   ii. Remove empty column from dataframe.
# Remove empty column from dataframe
df <- subset(df, select = -c(X__1))
   iii. Remove last 4 rows of dataframe.
# Remove last 4 rows of dataframe
n <- dim(df)[1]
df <- df[1:(n-4), ]
   iv. Remove asterisks (*) from dataframe and replace them with ""
# Remove asterisks (*) from dataframe and replace with ""
df <- lapply(df, function(x) {
  gsub("\\*", "", x)
})
   v. Replace any record that is "" with NA.
# Replace any record that is "" with NA
df[df == ""] <- NA
   vi. Rename columns of dataframe for clarity and simplicity.
# Rename columns of dataframe
colnames(df) <- c("state", "number_of_schools", "total_takers", "yield_per_teacher", 
                  "total_passed", "percent_passed", 
                  "total_female","total_female_passed", "percent_female_passed", "percent_female_taking", 
                  "total_black", "total_black_passed", "percent_black_passed", "percent_black_taking", "percent_black_state", "attempt_rate_black", 
                  "total_black_females", "total_black_females_passed", "percent_black_females_passed", 
                  "total_hispanic", "total_hispanic_passed", "percent_hispanic_passed", 
                  "total_hispanic_female", "total_hispanic_female_passed", "percent_hispanic_female_passed", "percent_hispanic_taking", "percent_hispanic_state", "attempt_rate_hispanic")
   vii. Generate a cleaned up dataset called "ap_cs_2013_states_clean.csv"
# Write finished dataframe to csv file
write.csv(df, file = "ap_cs_2013_states_clean.csv", row.names=FALSE, na="")
  1. In order to join the AP CS 2013 dataset to the 2015 Income Census data, we ran a query on data.world in order to rename the columns for simplicity, and we downloaded it as “acs-2015-5-e-income-queried.csv”.
  2. Use Tableau’s web data connector to import the datasets. Join the two datasets together by State to merge the datasets in order for us to explore the relationship between two datasets.
  3. We had to set the “S17 DV Project 6” data.world datasets PUBLIC in order to access and work on it in RStudio when we wrote the server code.
  4. Use SQL and R SDK in order to create the similar and other visualizations with ggplot.
  5. Create the Shiny App which includes all of the different types of visualizations, and publish it onto the Shiny server.

Cleaned Dataset

This is the AP CS Test dataset after the cleaning process:

Visualizations

Visualizations were created using both Tableau and R Shiny.

Box Plots

Insight for Figure 1: Yield Per Teacher by Region
These boxplots compare the distributions of test takers per teacher between each region. The distributions are not drastically different overall. Their spreads are rather similar, and it seems that the median ratio hovers around 10 test takers per teacher.

It seems as though the Northeast has a lower test taker to teacher ratio than the other regions. The South certainly has the most variation in its distribution, as well as possessing the highest median test taker to teacher ratio. All but one distribution contain no outliers. The West region contains two, with each being at opposite extremes of the test taker per teacher metric.

This boxplot displays the distribution of yield per teacher in each region. For West region, the points are relatively concentrated however there is an outlier(California).

Histogram

Insight for Figure 2: Score Distributions for Coastal and Landlocked States
We wanted to see if there was a significant difference in the distributions in the AP score counts between US states that are geographically coastal and those that are geographically landlocked. We noticed that the distributions are almost identical, suggesting that the geography of test takers has little to do with the AP score outcomes. Also, both distributions are bimodal and almost symmetric.

Scatter Plots

Insight for Figure 3 - 6: Female Pass Rate Related to Student Teacher Ratio by Region
This scatterplot demonstrates the relationship between the Exam pass rate for both Female,Male and the number of exam takers per teacher. We made scatterplot for each region, Midwest, Northeast, South and West. The line in each page is the trend line for the rate in each region.

In Midwest and Northeast, the pass rates tend to decrease as the number of students each teacher has increases. For South region, the female pass rate is tend to decrease however male pass rate tend to increase with number of students per teacher going up. Interestingly, in West region, with larger number of students per teacher, the pass rate for both female and male would be higher.

Cross Tabs

Insight for Figure 7: AP Score by States Colored by Passed rate level
This crosstab shows the number of people in each score category for individual states colored by KPI passed rate level. Passed rate between 0 and 60 percent is considered as low passed rate. Rate between 60 and 75 percent is set to be medium pass rate. Passed rate that is higher than 75 percent is considered high.California and Texas are the two states with largest number of AP CS exam takers and score 5 people.

AP Score by States Colored by Passed rate level Filtered by High per capita income states We first select per capita income and states columns to make a bar-chart, pick 9 states with the highest per capita income and create a high per capita income states set. The crosstab shows the number of people in each score category for each of the 9 states. The KPI is created using passed rate level parameter. With a relatively high per capita income, these states all have a medium to high passed rate on AP CS exam.

Barcharts

Insight for Figure 8: Taking rate for Black, Hispanic and other in high income states.
First create a barcharts by selecting median household income and Area name(state) columns from the income census data. Select the 12 highest median household income states and create a high income states sets.

This barchart displays the percentage of total test takers from Black, Hispanic and other race groups in each state, for states with a median household income greater than $60,000.In each state, Blacks and Hispanics exam takers are way less than other race groups. We noticed that Maryland had the largest proportion of Black test takers. California, which is along the border with Mexico, has a relatively higher percentage of Hispanic test takers.Lastly, Alaska and Utah had no blacks or hispanics that took the test, but this is most likely due to the fact that they have relatively low percentages of black and hispanic residents

Insight for Figure 9: Passed rate for Male and Female in high passed rate states
First create a barchart by selecting female and male percent passed and states columns from AP CS states data. Create a high household income states sets by setting the lower bound of high median household income as 60000.

This barchart displays the different passed rates for male and female in each of these 12 states that have the highest median household income. In each of the 12 high income states, males generally outperform females. The reference line displays the average passed rate for all 50 states. For these high income states except for Utah and Hawaii, male passed rate exceeds the overall average rate. However, Female passed rates are generally below the average.

Maps

Insight for Figure 10: Map of Income Inequality in the U.S.
Using the census data, we created a choropleth map displaying the Gini index in the US. This map was created using Ari Lamstein’s Choroplethr and Ezra Haber Glenn’s ACS packages. The classes are created using the Jenks natural breaks classification method.

The Gini index is a normalized measure of income inequality. We observed that many coastal states have generally higher index values than landlocked states, which compelled us to examine the AP CS score distributions between coastal and landlocked states, as seen in the histogram tab.

Insight for Figure 11: Map of Taking Rate for Hispanic
This map shows the Hispanic taking rate in each states. Percent Hispanic taking is the number of Hispanic exam takers as a percentage of total number of takers in this state. Colored and Labeled with the percent Hispanic taking. Darker Blue means a higher Hispanic taking rate, lighter color means low Hispanic taking percentage. South region has a relatively high Hispanic taking rate.

Insight for Figure 12: Map of Taking Rate for Blacks
This map shows the Black taking rate in each states. Percent Black taking is the number of Black exam takers as a percentage of total number of takers in this state. Colored and Labeled with the percent black taking. Darker orange means a higher Black taking rate, lighter color means low Black taking percentage. Southeast region has a relatively high Black taking rate.

Shiny App

To view our Shiny web app we made for the project, please click the image below. It contains other interesting visualizations that are not shown in this notebook. Shiny

LS0tCnRpdGxlOiAiQW5hbHl6aW5nIHRoZSAyMDEzIEFQIENTIFRlc3QgUmVwb3J0IGFuZCB0aGUgMjAxNSBJbmNvbWUgQ2Vuc3VzIERhdGEiCmF1dGhvcjogQSBDb2xsYWJvcmF0aXZlIFByb2plY3QgYnkgQW5kcmV3IENob3UsIEphZHkgWmVuZywgQWxleGlzIFpoYW5nLCBhbmQgUm9uZ2hhbwogIFpoYW5nCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IG5vCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6ICcyJwotLS0KCiMjICBSIENvbmZpZ3VyYXRpb24KQmVsb3cgd2UgZGlzcGxheSBvdXIgc2Vzc2lvbkluZm8oKS4KYGBge3Igc2Vzc2lvbkluZm99CnNlc3Npb25JbmZvKHBhY2thZ2U9TlVMTCkKYGBgCgohW10oLi4vMDMgVmlzdWFsaXphdGlvbnMvY292ZXIuanBlZykKCiMjICBPdXIgRGF0YXNldHMKPiBUaGUgZmlyc3QgW2RhdGFzZXRdKGh0dHA6Ly9ob21lLmNjLmdhdGVjaC5lZHUvaWNlLWd0LzU1NikgCj4gd2FzIGNyZWF0ZWQgYnkgc3R1ZGVudHMgYXQgR2VvcmdpYSBUZWNoIFVuaXZlcnNpdHkuIEl0IGZvY3VzZXMgb24gdGhlIGRlbW9ncmFwaGljcyBvZiB0ZXN0LXRha2VycyBmb3IgdGhlIEFQIENTIHRlc3QgYWRtaW5pc3RlcmVkIGJ5IHRoZSBDb2xsZWdlYm9hcmQgaW4gMjAxMy4gVGhlIGxvd2VzdCBzY29yZSBmb3IgYW4gQVAgdGVzdCBpcyBhIDEsIHdoaWxlIHRoZSBoaWdoZXN0IHNjb3JlIGlzIGEgNS4KPiBUaGUgc2Vjb25kIGRhdGFzZXQgdGhhdCB3ZSB1c2VkIHRvIGpvaW4gdGhlIEFQIGRhdGFzZXQgY29udGFpbnMgY2Vuc3VzIGRhdGEgcmVsYXRlZCB0byBpbmNvbWUgaW4gdGhlIFUuUyBpbiAyMDE1Lgo+IERvd25sb2FkIEFQIGRhdGFzZXQgW2hlcmVdKGh0dHA6Ly9ob21lLmNjLmdhdGVjaC5lZHUvaWNlLWd0L3VwbG9hZHMvNTU2L0RldGFpbGVkU3RhdGVJbmZvQVAtQ1MtQS0yMDA2LTIwMTMtd2l0aC1QZXJjZW50QmxhY2tBbmRISXNwYW5pY0J5U3RhdGUtZml4ZWQueGxzeCkuCj4gRG93bmxvYWQgdGhlIDIwMTUgVVMgQ2Vuc3VzIEluY29tZSBkYXRhIFtVUyBDZW5zdXMgcG9wdWxhdGlvbiBlc3RpbWF0ZXMsIEluY29tZSAoQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSwgMjAxMS0yMDE1KV0oaHR0cHM6Ly9kYXRhLndvcmxkL3VzY2Vuc3VzYnVyZWF1L2Fjcy0yMDE1LTUtZS1pbmNvbWUpCgoKIyMjICBBUCBUZXN0IERhdGFzZXQgQ29sdW1ucwpNZWFzdXJlIHwgRGVzY3JpcHRpb24KLS0tLS0tLS0tLS0tLS0tLS0tIHwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCjIwMTMgZGF0YSAgfCBUaGUgVS5TLiBTdGF0ZXMKIyBzY2hvb2xzICB8IE51bWJlciBvZiBzY2hvb2wgdGhhdCBvZmZlciBBUCBDUyB0ZXN0cyAKVG90YWwgIyB8IE51bWJlciBvZiBBUCBDUyB0ZXN0IHRha2VycwpZaWVsZCBwZXIgdGVhY2hlciB8IE51bWJlciBvZiBzdHVkZW50IHRlc3QgdGFrZXJzIHBlciB0ZWFjaGVyCiMgcGFzc2VkIHwgVGhlIG51bWJlciBvZiB0ZXN0IHRha2VycyB3aG8gc2NvcmVkIDMgb3V0IG9mIDUgb3IgYWJvdmUKJSBwYXNzZWQgfCBUaGUgcGVyY2VudGFnZSBvZiBwYXNzZWQgdGVzdCB0YWtlcnMgb3ZlciB0aGUgdG90YWwgbnVtYmVyIG9mIHRlc3QgdGFrZXJzCiMgZmVtYWxlIHwgVGhlIG51bWJlciBvZiBmZW1hbGUgdGVzdCB0YWtlcgojIGZlbWFsZSBwYXNzZWR8IFRoZSBudW1iZXIgb2YgZmVtYWxlIHRlc3QgdGFrZXIgd2hvIHNjb3JlZCAzIG91dCBvZiA1IG9yIGFib3ZlCiUgZmVtYWxlIHBhc3NlZHwgVGhlIHBlcmNlbnRhZ2Ugb2YgcGFzc2VkIGZlbWFsZSB0ZXN0IHRha2VycyBvdmVyIHRoZSB0b3RhbCBudW1iZXIgb2YgZmVtYWxlIHRlc3QgdGFrZXJzCiUgZmVtYWxlIHwgVGhlIHBlcmNlbnRhZ2Ugb2YgZmVtYWxlIHRlc3QgdGFrZXJzIG92ZXIgdGhlIHRvdGFsIG51bWJlciBvZiB0ZXN0IHRha2VycyAKIyBCbGFjayB8IFRoZSBudW1iZXIgb2YgYmxhY2sgdGVzdCB0YWtlcgojIEJsYWNrIFBhc3NlZHwgVGhlIG51bWJlciBvZiBibGFjayB0ZXN0IHRha2VyIHdobyBzY29yZWQgMyBvdXQgb2YgNSBvciBhYm92ZQolIEJsYWNrIHBhc3NlZHwgVGhlIHBlcmNlbnRhZ2Ugb2YgcGFzc2VkIGJsYWNrIHRlc3QgdGFrZXJzIG92ZXIgdGhlIHRvdGFsIG51bWJlciBvZiB0ZXN0IHRha2VycyAKJSBibGFjayBpbiBzdGF0ZSB8IFBlcmNlbnRhZ2Ugb2YgYmxhY2sgaW4gc3RhdGUgCiMgSGlzcGFuaWMgfCBUaGUgbnVtYmVyIG9mIEhpc3BhbmljIHRlc3QgdGFrZXIKIyBIaXNwYW5pYyBwYXNzZWQgfCBUaGUgbnVtYmVyIG9mIEhpc3BhbmljIHRlc3QgdGFrZXIgd2hvIHNjb3JlZCAzIG91dCBvZiA1IG9yIGFib3ZlCiUgSGlzcGFuaWMgcGFzc2VkIHwgVGhlIHBlcmNlbnRhZ2Ugb2YgcGFzc2VkIEhpc3BhbmljIHRlc3QgdGFrZXJzIG92ZXIgdGhlIHRvdGFsIG51bWJlciBvZiB0ZXN0IHRha2VycyAKJSBIaXNwYW5pYyBpbiBzdGF0ZSB8IFBlcmNlbnRhZ2Ugb2YgSGlzcGFuaWNzIGluIHN0YXRlCiUgdGFraW5nIC8gJSBzdGF0ZSAqIDEwMCB8IEF0dGVtcHQgcmF0ZSBvZiBIaXNwYW5pYyB0ZXN0IHRha2VycyAKCgojIyMgIENlbnN1cyBEYXRhc2V0IENvbHVtbnMgIApNZWFzdXJlIHwgRGVzY3JpcHRpb24KLS0tLS0tLS0tLS0tLS0tLS0tIHwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tClN0YXRlIHwgU3RhdGUgYWJicmV2aWF0aW9uCkFyZWFOYW1lIHwgU3RhdGUgZnVsbCBuYW1lIAptZWRpYW5faG91c2Vob2xkX2luY29tZSB8IE1lZGlhbiBob3VzZWhvbGQgaW5jb21lIGluIDIwMTUKcGVyX2NhcGl0YV9pbmNvbWUgfCBBIG1lYXN1cmVtZW50IGFuIGFyZWEncyBhdmVyYWdlIGluY29tZQpnaW5pX2luZGV4IHwgQSBtZWFzdXJlbWVudCBvZiBpbmVxdWFsaXR5LiAoMCBzdGFuZHMgZm9yIHBlcmZlY3QgZXF1YWxpdHkpCgojIyAgTWV0aG9kb2xvZ3kKIyMjIE9yaWdpbmFsIERhdGFzZXQKPiBUaGUgMjAxMyBBUCBDUyB0ZXN0IGRhdGFzZXQgYmVmb3JlIHRoZSBjbGVhbmluZyBwcm9jZXNzCgpgYGB7ciwgZWNobz0gRkFMU0UsIHdhcm5pbmc9IEZBTFNFLCBtZXNzYWdlPSBGQUxTRSwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NX0gCnNvdXJjZSgiLi4vMDEgRGF0YS9vcmlnaW5hbF9kYXRhLlIiKQpgYGAKCgojIyMgRVRMIExvZ2ljCgogICA+IDEuIEFzIHNlZW4gZnJvbSB0aGUgcHJldmlvdXMgdGFibGUsIHRoZSB1bmNsZWFuZWQgQVAgQ1MgZGF0YSBpcyBmaWxsZWQgdXAgd2l0aCBlbXB0eSBjb2x1bW5zLCBhc3Rlcmlza3MgYW5kIG11bHRpcGxlIGNvbHVtbnMgdGhhdCB3ZSB3aWxsIG5vdCB1c2UgaW4gb3VyIGRhdGEgdmlzdWFsaXphdGlvbi4gV2UgZm9sbG93ZWQgdGhlIGZvbGxvd2luZyBwcm9jZXNzIHRvIGNsZWFuIHVwIHRoZSBkYXRhOgogICAKICAgICAgIGkuIEJ1aWxkIGFuIEVUTCBzY3JpcHQgdG8gcHVsbCB0aGUgZGF0YSBmcm9tIGRhdGEud29ybGQgYW5kIHByb2NlZWQgdGhlIGNsZWFuaW5nIHByb2Nlc3MgCmBgYHtyLCBldmFsPUZBTFNFfQojIyMgTG9hZCBSZXF1aXJlZCBQYWNrYWdlcwpyZXF1aXJlKHJlYWR4bCkKIyBTZXQgdGhlIHdvcmtpbmcgZGlyZWN0b3J5IHRvIGFjY2VzcyBDU1ZzCnNldHdkKCJ+L3MxN2R2ZmluYWxwcm9qZWN0LWR2cHJvamVjdC00LWNob3UtemVuZy16aGFuZy16aGFuZy8wMSBEYXRhIikKCiMgZGYgPC0gcmVhZF9leGNlbCgiLi8wMSBEYXRhL0RldGFpbGVkU3RhdGVJbmZvQVAtQ1MtQS0yMDA2LTIwMTMtd2l0aC1QZXJjZW50QmxhY2tBbmRISXNwYW5pY0J5U3RhdGUtZml4ZWQueGxzeCIsIHNoZWV0ID0gIlNoZWV0MiIpCmRmIDwtIHJlYWRfZXhjZWwoIi4uLzAxIERhdGEvRGV0YWlsZWRTdGF0ZUluZm9BUC1DUy1BLTIwMDYtMjAxMy13aXRoLVBlcmNlbnRCbGFja0FuZEhJc3BhbmljQnlTdGF0ZS1maXhlZC54bHN4Iiwgc2hlZXQgPSAiU2hlZXQyIikKYGBgCiAgICAgICBpaS4gUmVtb3ZlIGVtcHR5IGNvbHVtbiBmcm9tIGRhdGFmcmFtZS4KYGBge3IsIGV2YWw9RkFMU0V9CiMgUmVtb3ZlIGVtcHR5IGNvbHVtbiBmcm9tIGRhdGFmcmFtZQpkZiA8LSBzdWJzZXQoZGYsIHNlbGVjdCA9IC1jKFhfXzEpKQpgYGAKICAgICAgIGlpaS4gUmVtb3ZlIGxhc3QgNCByb3dzIG9mIGRhdGFmcmFtZS4KYGBge3IsIGV2YWw9RkFMU0V9CiMgUmVtb3ZlIGxhc3QgNCByb3dzIG9mIGRhdGFmcmFtZQpuIDwtIGRpbShkZilbMV0KZGYgPC0gZGZbMToobi00KSwgXQpgYGAKICAgICAgIGl2LiBSZW1vdmUgYXN0ZXJpc2tzICgqKSBmcm9tIGRhdGFmcmFtZSBhbmQgcmVwbGFjZSB0aGVtIHdpdGggIiIKYGBge3IsIGV2YWw9RkFMU0V9CiMgUmVtb3ZlIGFzdGVyaXNrcyAoKikgZnJvbSBkYXRhZnJhbWUgYW5kIHJlcGxhY2Ugd2l0aCAiIgpkZiA8LSBsYXBwbHkoZGYsIGZ1bmN0aW9uKHgpIHsKICBnc3ViKCJcXCoiLCAiIiwgeCkKfSkKYGBgCiAgICAgICB2LiBSZXBsYWNlIGFueSByZWNvcmQgdGhhdCBpcyAiIiB3aXRoIE5BLgpgYGB7ciwgZXZhbD1GQUxTRX0KIyBSZXBsYWNlIGFueSByZWNvcmQgdGhhdCBpcyAiIiB3aXRoIE5BCmRmW2RmID09ICIiXSA8LSBOQQpgYGAKICAgICAgIHZpLiBSZW5hbWUgY29sdW1ucyBvZiBkYXRhZnJhbWUgZm9yIGNsYXJpdHkgYW5kIHNpbXBsaWNpdHkuCmBgYHtyLCBldmFsPUZBTFNFfQojIFJlbmFtZSBjb2x1bW5zIG9mIGRhdGFmcmFtZQpjb2xuYW1lcyhkZikgPC0gYygic3RhdGUiLCAibnVtYmVyX29mX3NjaG9vbHMiLCAidG90YWxfdGFrZXJzIiwgInlpZWxkX3Blcl90ZWFjaGVyIiwgCiAgICAgICAgICAgICAgICAgICJ0b3RhbF9wYXNzZWQiLCAicGVyY2VudF9wYXNzZWQiLCAKICAgICAgICAgICAgICAgICAgInRvdGFsX2ZlbWFsZSIsInRvdGFsX2ZlbWFsZV9wYXNzZWQiLCAicGVyY2VudF9mZW1hbGVfcGFzc2VkIiwgInBlcmNlbnRfZmVtYWxlX3Rha2luZyIsIAogICAgICAgICAgICAgICAgICAidG90YWxfYmxhY2siLCAidG90YWxfYmxhY2tfcGFzc2VkIiwgInBlcmNlbnRfYmxhY2tfcGFzc2VkIiwgInBlcmNlbnRfYmxhY2tfdGFraW5nIiwgInBlcmNlbnRfYmxhY2tfc3RhdGUiLCAiYXR0ZW1wdF9yYXRlX2JsYWNrIiwgCiAgICAgICAgICAgICAgICAgICJ0b3RhbF9ibGFja19mZW1hbGVzIiwgInRvdGFsX2JsYWNrX2ZlbWFsZXNfcGFzc2VkIiwgInBlcmNlbnRfYmxhY2tfZmVtYWxlc19wYXNzZWQiLCAKICAgICAgICAgICAgICAgICAgInRvdGFsX2hpc3BhbmljIiwgInRvdGFsX2hpc3BhbmljX3Bhc3NlZCIsICJwZXJjZW50X2hpc3BhbmljX3Bhc3NlZCIsIAogICAgICAgICAgICAgICAgICAidG90YWxfaGlzcGFuaWNfZmVtYWxlIiwgInRvdGFsX2hpc3BhbmljX2ZlbWFsZV9wYXNzZWQiLCAicGVyY2VudF9oaXNwYW5pY19mZW1hbGVfcGFzc2VkIiwgInBlcmNlbnRfaGlzcGFuaWNfdGFraW5nIiwgInBlcmNlbnRfaGlzcGFuaWNfc3RhdGUiLCAiYXR0ZW1wdF9yYXRlX2hpc3BhbmljIikKYGBgCiAgICAgICB2aWkuIEdlbmVyYXRlIGEgY2xlYW5lZCB1cCBkYXRhc2V0IGNhbGxlZCAiYXBfY3NfMjAxM19zdGF0ZXNfY2xlYW4uY3N2IgpgYGB7ciwgZXZhbD1GQUxTRX0KIyBXcml0ZSBmaW5pc2hlZCBkYXRhZnJhbWUgdG8gY3N2IGZpbGUKd3JpdGUuY3N2KGRmLCBmaWxlID0gImFwX2NzXzIwMTNfc3RhdGVzX2NsZWFuLmNzdiIsIHJvdy5uYW1lcz1GQUxTRSwgbmE9IiIpCmBgYCAgICAgICAKICAgPjIuIEluIG9yZGVyIHRvIGpvaW4gdGhlIEFQIENTIDIwMTMgZGF0YXNldCB0byB0aGUgMjAxNSBJbmNvbWUgQ2Vuc3VzIGRhdGEsIHdlIHJhbiBhIHF1ZXJ5IG9uIGRhdGEud29ybGQgaW4gb3JkZXIgdG8gcmVuYW1lIHRoZSBjb2x1bW5zIGZvciBzaW1wbGljaXR5LCBhbmQgd2UgZG93bmxvYWRlZCBpdCBhcyAiYWNzLTIwMTUtNS1lLWluY29tZS1xdWVyaWVkLmNzdiIuCiAgID4zLiBVc2UgVGFibGVhdSdzIHdlYiBkYXRhIGNvbm5lY3RvciB0byBpbXBvcnQgdGhlIGRhdGFzZXRzLiBKb2luIHRoZSB0d28gZGF0YXNldHMgdG9nZXRoZXIgYnkgU3RhdGUgdG8gbWVyZ2UgdGhlIGRhdGFzZXRzIGluIG9yZGVyIGZvciB1cyB0byBleHBsb3JlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gZGF0YXNldHMuCiAgID40LiBXZSBoYWQgdG8gc2V0IHRoZSAiUzE3IERWIFByb2plY3QgNiIgZGF0YS53b3JsZCBkYXRhc2V0cyBQVUJMSUMgaW4gb3JkZXIgdG8gYWNjZXNzIGFuZCB3b3JrIG9uIGl0IGluIFJTdHVkaW8gd2hlbiB3ZSB3cm90ZSB0aGUgc2VydmVyIGNvZGUuCiAgID41LiBVc2UgU1FMIGFuZCBSIFNESyBpbiBvcmRlciB0byBjcmVhdGUgdGhlIHNpbWlsYXIgYW5kIG90aGVyIHZpc3VhbGl6YXRpb25zIHdpdGggZ2dwbG90LiAKICAgPjYuIENyZWF0ZSB0aGUgU2hpbnkgQXBwIHdoaWNoIGluY2x1ZGVzIGFsbCBvZiB0aGUgZGlmZmVyZW50IHR5cGVzIG9mIHZpc3VhbGl6YXRpb25zLCBhbmQgcHVibGlzaCBpdCBvbnRvIHRoZSBTaGlueSBzZXJ2ZXIuCgojIyMgQ2xlYW5lZCBEYXRhc2V0Cj4gVGhpcyBpcyB0aGUgQVAgQ1MgVGVzdCBkYXRhc2V0IGFmdGVyIHRoZSBjbGVhbmluZyBwcm9jZXNzOgoKYGBge3IsIGVjaG89IEZBTFNFLCB3YXJuaW5nPSBGQUxTRSwgbWVzc2FnZT0gRkFMU0UsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTV9IApzb3VyY2UoIi4uLzAxIERhdGEvZXRsX2ZpbmFsX3Byb2plY3QuUiIpCmBgYAoKCiMjICBWaXN1YWxpemF0aW9ucwpWaXN1YWxpemF0aW9ucyB3ZXJlIGNyZWF0ZWQgdXNpbmcgYm90aCBUYWJsZWF1IGFuZCBSIFNoaW55LiAKCiMjIyAgQm94IFBsb3RzCiFbXSguLi8wMyBWaXN1YWxpemF0aW9ucy9Cb3hQbG90VGFrZXJzUGVyVGVhY2hlci5wbmcpCgo+ICoqSW5zaWdodCBmb3IgRmlndXJlIDE6ICpZaWVsZCBQZXIgVGVhY2hlciBieSBSZWdpb24qICoqICAKVGhlc2UgYm94cGxvdHMgY29tcGFyZSB0aGUgZGlzdHJpYnV0aW9ucyBvZiB0ZXN0IHRha2VycyBwZXIgdGVhY2hlciBiZXR3ZWVuIGVhY2ggcmVnaW9uLiBUaGUgZGlzdHJpYnV0aW9ucyBhcmUgbm90IGRyYXN0aWNhbGx5IGRpZmZlcmVudCBvdmVyYWxsLiBUaGVpciBzcHJlYWRzIGFyZSByYXRoZXIgc2ltaWxhciwgYW5kIGl0IHNlZW1zIHRoYXQgdGhlIG1lZGlhbiByYXRpbyBob3ZlcnMgYXJvdW5kIDEwIHRlc3QgdGFrZXJzIHBlciB0ZWFjaGVyLgoKPiBJdCBzZWVtcyBhcyB0aG91Z2ggdGhlIE5vcnRoZWFzdCBoYXMgYSBsb3dlciB0ZXN0IHRha2VyIHRvIHRlYWNoZXIgcmF0aW8gdGhhbiB0aGUgb3RoZXIgcmVnaW9ucy4gVGhlIFNvdXRoIGNlcnRhaW5seSBoYXMgdGhlIG1vc3QgdmFyaWF0aW9uIGluIGl0cyBkaXN0cmlidXRpb24sIGFzIHdlbGwgYXMgcG9zc2Vzc2luZyB0aGUgaGlnaGVzdCBtZWRpYW4gdGVzdCB0YWtlciB0byB0ZWFjaGVyIHJhdGlvLiBBbGwgYnV0IG9uZSBkaXN0cmlidXRpb24gY29udGFpbiBubyBvdXRsaWVycy4gVGhlIFdlc3QgcmVnaW9uIGNvbnRhaW5zIHR3bywgd2l0aCBlYWNoIGJlaW5nIGF0IG9wcG9zaXRlIGV4dHJlbWVzIG9mIHRoZSB0ZXN0IHRha2VyIHBlciB0ZWFjaGVyIG1ldHJpYy4KCj4gVGhpcyBib3hwbG90IGRpc3BsYXlzIHRoZSBkaXN0cmlidXRpb24gb2YgeWllbGQgcGVyIHRlYWNoZXIgaW4gZWFjaCByZWdpb24uCkZvciBXZXN0IHJlZ2lvbiwgdGhlIHBvaW50cyBhcmUgcmVsYXRpdmVseSBjb25jZW50cmF0ZWQgaG93ZXZlciB0aGVyZSBpcyBhbiBvdXRsaWVyKENhbGlmb3JuaWEpLiAgCgojIyMgSGlzdG9ncmFtCiFbXSguLi8wMyBWaXN1YWxpemF0aW9ucy9IaXN0b2dyYW0ucG5nKQoKPiAqKkluc2lnaHQgZm9yIEZpZ3VyZSAyOiAqU2NvcmUgRGlzdHJpYnV0aW9ucyBmb3IgQ29hc3RhbCBhbmQgTGFuZGxvY2tlZCBTdGF0ZXMqICoqICAKV2Ugd2FudGVkIHRvIHNlZSBpZiB0aGVyZSB3YXMgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHRoZSBkaXN0cmlidXRpb25zIGluIHRoZSBBUCBzY29yZSBjb3VudHMgYmV0d2VlbiBVUyBzdGF0ZXMgdGhhdCBhcmUgZ2VvZ3JhcGhpY2FsbHkgY29hc3RhbCBhbmQgdGhvc2UgdGhhdCBhcmUgZ2VvZ3JhcGhpY2FsbHkgbGFuZGxvY2tlZC4gV2Ugbm90aWNlZCB0aGF0IHRoZSBkaXN0cmlidXRpb25zIGFyZSBhbG1vc3QgaWRlbnRpY2FsLCBzdWdnZXN0aW5nIHRoYXQgdGhlIGdlb2dyYXBoeSBvZiB0ZXN0IHRha2VycyBoYXMgbGl0dGxlIHRvIGRvIHdpdGggdGhlIEFQIHNjb3JlIG91dGNvbWVzLiBBbHNvLCBib3RoIGRpc3RyaWJ1dGlvbnMgYXJlIGJpbW9kYWwgYW5kIGFsbW9zdCBzeW1tZXRyaWMuCgoKIyMjIFNjYXR0ZXIgUGxvdHMKCiFbXSguLi8wMyBWaXN1YWxpemF0aW9ucy9wYXNzcmF0ZXBlcnRlYWNoZXJtaWR3ZXN0LnBuZykKCiFbXSguLi8wMyBWaXN1YWxpemF0aW9ucy9wYXNzcmF0ZXBlcnRlYWNoZXJOb3J0aGVhc3QucG5nKQohW10oLi4vMDMgVmlzdWFsaXphdGlvbnMvcGFzc3JhdGVwZXJ0ZWFjaGVyc291dGgucG5nKQohW10oLi4vMDMgVmlzdWFsaXphdGlvbnMvcGFzc3JhdGVwZXJ0ZWFjaGVyd2VzdC5wbmcpCgo+ICoqSW5zaWdodCBmb3IgRmlndXJlIDMgLSA2OiAqRmVtYWxlIFBhc3MgUmF0ZSBSZWxhdGVkIHRvIFN0dWRlbnQgVGVhY2hlciBSYXRpbyBieSBSZWdpb24qICoqICAKVGhpcyBzY2F0dGVycGxvdCBkZW1vbnN0cmF0ZXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBFeGFtIHBhc3MgcmF0ZSBmb3IgYm90aCBGZW1hbGUsTWFsZSBhbmQgdGhlIG51bWJlciBvZiBleGFtIHRha2VycyBwZXIgdGVhY2hlci4gV2UgbWFkZSBzY2F0dGVycGxvdCBmb3IgZWFjaCByZWdpb24sIE1pZHdlc3QsIE5vcnRoZWFzdCwgU291dGggYW5kIFdlc3QuIFRoZSBsaW5lIGluIGVhY2ggcGFnZSBpcyB0aGUgdHJlbmQgbGluZSBmb3IgdGhlIHJhdGUgaW4gZWFjaCByZWdpb24uIAoKPiBJbiBNaWR3ZXN0IGFuZCBOb3J0aGVhc3QsIHRoZSBwYXNzIHJhdGVzIHRlbmQgdG8gZGVjcmVhc2UgYXMgdGhlIG51bWJlciBvZiBzdHVkZW50cyBlYWNoIHRlYWNoZXIgaGFzIGluY3JlYXNlcy4gRm9yIFNvdXRoIHJlZ2lvbiwgdGhlIGZlbWFsZSBwYXNzIHJhdGUgaXMgdGVuZCB0byBkZWNyZWFzZSBob3dldmVyIG1hbGUgcGFzcyByYXRlIHRlbmQgdG8gaW5jcmVhc2Ugd2l0aCBudW1iZXIgb2Ygc3R1ZGVudHMgcGVyIHRlYWNoZXIgZ29pbmcgdXAuIEludGVyZXN0aW5nbHksIGluIFdlc3QgcmVnaW9uLCB3aXRoIGxhcmdlciBudW1iZXIgb2Ygc3R1ZGVudHMgcGVyIHRlYWNoZXIsIHRoZSBwYXNzIHJhdGUgZm9yIGJvdGggZmVtYWxlIGFuZCBtYWxlIHdvdWxkIGJlIGhpZ2hlci4gCgoKIyMjIENyb3NzIFRhYnMKIVtdKC4uLzAzIFZpc3VhbGl6YXRpb25zL0Nyb3NzdGFiQVBTY29yZWJ5U3RhdGVDb2xvcmVkYnlQYXNzZWRSYXRlLnBuZykKCj4gKipJbnNpZ2h0IGZvciBGaWd1cmUgNzogKkFQIFNjb3JlIGJ5IFN0YXRlcyBDb2xvcmVkIGJ5IFBhc3NlZCByYXRlIGxldmVsKiAqKiAgClRoaXMgY3Jvc3N0YWIgc2hvd3MgdGhlIG51bWJlciBvZiBwZW9wbGUgaW4gZWFjaCBzY29yZSBjYXRlZ29yeSBmb3IgaW5kaXZpZHVhbCBzdGF0ZXMgY29sb3JlZCBieSBLUEkgcGFzc2VkIHJhdGUgbGV2ZWwuIFBhc3NlZCByYXRlIGJldHdlZW4gMCBhbmQgNjAgcGVyY2VudCBpcyBjb25zaWRlcmVkIGFzIGxvdyBwYXNzZWQgcmF0ZS4gUmF0ZSBiZXR3ZWVuIDYwIGFuZCA3NSBwZXJjZW50IGlzIHNldCB0byBiZSBtZWRpdW0gcGFzcyByYXRlLiBQYXNzZWQgcmF0ZSB0aGF0IGlzIGhpZ2hlciB0aGFuIDc1IHBlcmNlbnQgaXMgY29uc2lkZXJlZCBoaWdoLkNhbGlmb3JuaWEgYW5kIFRleGFzIGFyZSB0aGUgdHdvIHN0YXRlcyB3aXRoIGxhcmdlc3QgbnVtYmVyIG9mIEFQIENTIGV4YW0gdGFrZXJzIGFuZCBzY29yZSA1IHBlb3BsZS4gIAoKPiBBUCBTY29yZSBieSBTdGF0ZXMgQ29sb3JlZCBieSBQYXNzZWQgcmF0ZSBsZXZlbCBGaWx0ZXJlZCBieSBIaWdoIHBlciBjYXBpdGEgaW5jb21lIHN0YXRlcwpXZSBmaXJzdCBzZWxlY3QgcGVyIGNhcGl0YSBpbmNvbWUgYW5kIHN0YXRlcyBjb2x1bW5zIHRvIG1ha2UgYSBiYXItY2hhcnQsIHBpY2sgOSBzdGF0ZXMgd2l0aCB0aGUgaGlnaGVzdCBwZXIgY2FwaXRhIGluY29tZSAgYW5kIGNyZWF0ZSBhIGhpZ2ggcGVyIGNhcGl0YSBpbmNvbWUgc3RhdGVzIHNldC4gClRoZSBjcm9zc3RhYiBzaG93cyB0aGUgbnVtYmVyIG9mIHBlb3BsZSBpbiBlYWNoIHNjb3JlIGNhdGVnb3J5IGZvciBlYWNoIG9mIHRoZSA5IHN0YXRlcy4gVGhlIEtQSSBpcyBjcmVhdGVkIHVzaW5nIHBhc3NlZCByYXRlIGxldmVsIHBhcmFtZXRlci4gV2l0aCBhIHJlbGF0aXZlbHkgaGlnaCBwZXIgY2FwaXRhIGluY29tZSwgdGhlc2Ugc3RhdGVzIGFsbCBoYXZlIGEgbWVkaXVtIHRvIGhpZ2ggcGFzc2VkIHJhdGUgb24gQVAgQ1MgZXhhbS4gCgojIyMgQmFyY2hhcnRzCiFbXSguLi8wMyBWaXN1YWxpemF0aW9ucy9CYXJjaGFyRGlmZmVyZW50VGFraW5nUmF0ZXNieUhpZ2hJbmNvbWVTdGF0ZXMucG5nKQoKPiAqKkluc2lnaHQgZm9yIEZpZ3VyZSA4OiAqVGFraW5nIHJhdGUgZm9yIEJsYWNrLCBIaXNwYW5pYyBhbmQgb3RoZXIgaW4gaGlnaCBpbmNvbWUgc3RhdGVzLiogKiogIApGaXJzdCBjcmVhdGUgYSBiYXJjaGFydHMgYnkgc2VsZWN0aW5nIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIGFuZCBBcmVhIG5hbWUoc3RhdGUpIGNvbHVtbnMgZnJvbSB0aGUgaW5jb21lIGNlbnN1cyBkYXRhLiBTZWxlY3QgdGhlIDEyIGhpZ2hlc3QgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgc3RhdGVzIGFuZCBjcmVhdGUgYSBoaWdoIGluY29tZSBzdGF0ZXMgc2V0cy4KCj4gVGhpcyBiYXJjaGFydCBkaXNwbGF5cyB0aGUgcGVyY2VudGFnZSBvZiB0b3RhbCB0ZXN0IHRha2VycyBmcm9tIEJsYWNrLCBIaXNwYW5pYyBhbmQgb3RoZXIgcmFjZSBncm91cHMgIGluIGVhY2ggc3RhdGUsIGZvciBzdGF0ZXMgd2l0aCBhIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIGdyZWF0ZXIgdGhhbiAkNjAsMDAwLkluIGVhY2ggc3RhdGUsIEJsYWNrcyBhbmQgSGlzcGFuaWNzIGV4YW0gdGFrZXJzIGFyZSB3YXkgbGVzcyB0aGFuIG90aGVyIHJhY2UgZ3JvdXBzLiBXZSBub3RpY2VkIHRoYXQgTWFyeWxhbmQgaGFkIHRoZSBsYXJnZXN0IHByb3BvcnRpb24gb2YgQmxhY2sgdGVzdCB0YWtlcnMuIENhbGlmb3JuaWEsIHdoaWNoIGlzIGFsb25nIHRoZSBib3JkZXIgd2l0aCBNZXhpY28sIGhhcyBhIHJlbGF0aXZlbHkgaGlnaGVyIHBlcmNlbnRhZ2Ugb2YgSGlzcGFuaWMgdGVzdCB0YWtlcnMuTGFzdGx5LCBBbGFza2EgYW5kIFV0YWggaGFkIG5vIGJsYWNrcyBvciBoaXNwYW5pY3MgdGhhdCB0b29rIHRoZSB0ZXN0LCBidXQgdGhpcyBpcyBtb3N0IGxpa2VseSBkdWUgdG8gdGhlIGZhY3QgdGhhdCB0aGV5IGhhdmUgcmVsYXRpdmVseSBsb3cgcGVyY2VudGFnZXMgb2YgYmxhY2sgYW5kIGhpc3BhbmljIHJlc2lkZW50cyAKCiFbXSguLi8wMyBWaXN1YWxpemF0aW9ucy9CYXJjaGFydFBhc3NlZFJhdGVieUdlbmRlci5wbmcpCgo+ICoqSW5zaWdodCBmb3IgRmlndXJlIDk6ICpQYXNzZWQgcmF0ZSBmb3IgTWFsZSBhbmQgRmVtYWxlIGluIGhpZ2ggcGFzc2VkIHJhdGUgc3RhdGVzKiAqKiAgCkZpcnN0IGNyZWF0ZSBhIGJhcmNoYXJ0IGJ5IHNlbGVjdGluZyBmZW1hbGUgYW5kIG1hbGUgcGVyY2VudCBwYXNzZWQgYW5kIHN0YXRlcyBjb2x1bW5zIGZyb20gQVAgQ1Mgc3RhdGVzIGRhdGEuIENyZWF0ZSBhIGhpZ2ggaG91c2Vob2xkIGluY29tZSBzdGF0ZXMgc2V0cyBieSBzZXR0aW5nIHRoZSBsb3dlciBib3VuZCBvZiBoaWdoIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIGFzIDYwMDAwLiAKCj4gVGhpcyBiYXJjaGFydCBkaXNwbGF5cyB0aGUgZGlmZmVyZW50IHBhc3NlZCByYXRlcyBmb3IgbWFsZSBhbmQgZmVtYWxlIGluIGVhY2ggb2YgdGhlc2UgMTIgc3RhdGVzIHRoYXQgaGF2ZSB0aGUgaGlnaGVzdCBtZWRpYW4gaG91c2Vob2xkIGluY29tZS4gSW4gZWFjaCBvZiB0aGUgMTIgaGlnaCBpbmNvbWUgc3RhdGVzLCBtYWxlcyBnZW5lcmFsbHkgb3V0cGVyZm9ybSBmZW1hbGVzLiBUaGUgcmVmZXJlbmNlIGxpbmUgZGlzcGxheXMgdGhlIGF2ZXJhZ2UgcGFzc2VkIHJhdGUgZm9yIGFsbCA1MCBzdGF0ZXMuIEZvciB0aGVzZSBoaWdoIGluY29tZSBzdGF0ZXMgZXhjZXB0IGZvciBVdGFoIGFuZCBIYXdhaWksIG1hbGUgcGFzc2VkIHJhdGUgZXhjZWVkcyB0aGUgb3ZlcmFsbCBhdmVyYWdlIHJhdGUuIEhvd2V2ZXIsIEZlbWFsZSBwYXNzZWQgcmF0ZXMgYXJlIGdlbmVyYWxseSBiZWxvdyB0aGUgYXZlcmFnZS4KCiMjIyBNYXBzCiFbXSguLi8wMyBWaXN1YWxpemF0aW9ucy9NYXAtU2hpbnkucG5nKQoKPiAqKkluc2lnaHQgZm9yIEZpZ3VyZSAxMDogKk1hcCBvZiBJbmNvbWUgSW5lcXVhbGl0eSBpbiB0aGUgVS5TLiogKiogIApVc2luZyB0aGUgY2Vuc3VzIGRhdGEsIHdlIGNyZWF0ZWQgYSBjaG9yb3BsZXRoIG1hcCBkaXNwbGF5aW5nIHRoZSBHaW5pIGluZGV4IGluIHRoZSBVUy4gVGhpcyBtYXAgd2FzIGNyZWF0ZWQgdXNpbmcgQXJpIExhbXN0ZWluJ3MgQ2hvcm9wbGV0aHIgYW5kIEV6cmEgSGFiZXIgR2xlbm4ncyBBQ1MgcGFja2FnZXMuIFRoZSBjbGFzc2VzIGFyZSBjcmVhdGVkIHVzaW5nIHRoZSBKZW5rcyBuYXR1cmFsIGJyZWFrcyBjbGFzc2lmaWNhdGlvbiBtZXRob2QuCgo+IFRoZSBHaW5pIGluZGV4IGlzIGEgbm9ybWFsaXplZCBtZWFzdXJlIG9mIGluY29tZSBpbmVxdWFsaXR5LiBXZSBvYnNlcnZlZCB0aGF0IG1hbnkgY29hc3RhbCBzdGF0ZXMgaGF2ZSBnZW5lcmFsbHkgaGlnaGVyIGluZGV4IHZhbHVlcyB0aGFuIGxhbmRsb2NrZWQgc3RhdGVzLCB3aGljaCBjb21wZWxsZWQgdXMgdG8gZXhhbWluZSB0aGUgQVAgQ1Mgc2NvcmUgZGlzdHJpYnV0aW9ucyBiZXR3ZWVuIGNvYXN0YWwgYW5kIGxhbmRsb2NrZWQgc3RhdGVzLCBhcyBzZWVuIGluIHRoZSBoaXN0b2dyYW0gdGFiLgoKIVtdKC4uLzAzIFZpc3VhbGl6YXRpb25zL01hcC1IaXNwYW5pY1Rha2luZy5wbmcpCgo+ICoqSW5zaWdodCBmb3IgRmlndXJlIDExOiAqTWFwIG9mIFRha2luZyBSYXRlIGZvciBIaXNwYW5pYyogKiogIApUaGlzIG1hcCBzaG93cyB0aGUgSGlzcGFuaWMgdGFraW5nIHJhdGUgaW4gZWFjaCBzdGF0ZXMuIFBlcmNlbnQgSGlzcGFuaWMgdGFraW5nIGlzIHRoZSBudW1iZXIgb2YgSGlzcGFuaWMgZXhhbSB0YWtlcnMgYXMgYSBwZXJjZW50YWdlIG9mIHRvdGFsIG51bWJlciBvZiB0YWtlcnMgaW4gdGhpcyBzdGF0ZS4gQ29sb3JlZCBhbmQgTGFiZWxlZCB3aXRoIHRoZSBwZXJjZW50IEhpc3BhbmljIHRha2luZy4gRGFya2VyIEJsdWUgbWVhbnMgYSBoaWdoZXIgSGlzcGFuaWMgdGFraW5nIHJhdGUsIGxpZ2h0ZXIgY29sb3IgbWVhbnMgbG93IEhpc3BhbmljIHRha2luZyBwZXJjZW50YWdlLiBTb3V0aCByZWdpb24gaGFzIGEgcmVsYXRpdmVseSBoaWdoIEhpc3BhbmljIHRha2luZyByYXRlLiAKCiFbXSguLi8wMyBWaXN1YWxpemF0aW9ucy9NYXAtQmxhY2tUYWtpbmcucG5nKQoKPiAqKkluc2lnaHQgZm9yIEZpZ3VyZSAxMjogKk1hcCBvZiBUYWtpbmcgUmF0ZSBmb3IgQmxhY2tzKiAqKiAgClRoaXMgbWFwIHNob3dzIHRoZSBCbGFjayB0YWtpbmcgcmF0ZSBpbiBlYWNoIHN0YXRlcy4gUGVyY2VudCBCbGFjayB0YWtpbmcgaXMgdGhlIG51bWJlciBvZiBCbGFjayBleGFtIHRha2VycyBhcyBhIHBlcmNlbnRhZ2Ugb2YgdG90YWwgbnVtYmVyIG9mIHRha2VycyBpbiB0aGlzIHN0YXRlLiBDb2xvcmVkIGFuZCBMYWJlbGVkIHdpdGggdGhlIHBlcmNlbnQgYmxhY2sgdGFraW5nLiBEYXJrZXIgb3JhbmdlIG1lYW5zIGEgaGlnaGVyIEJsYWNrIHRha2luZyByYXRlLCBsaWdodGVyIGNvbG9yIG1lYW5zIGxvdyBCbGFjayB0YWtpbmcgcGVyY2VudGFnZS4gU291dGhlYXN0IHJlZ2lvbiBoYXMgYSByZWxhdGl2ZWx5IGhpZ2ggQmxhY2sgdGFraW5nIHJhdGUuIAoKIyMgU2hpbnkgQXBwClRvIHZpZXcgb3VyIFNoaW55IHdlYiBhcHAgd2UgbWFkZSBmb3IgdGhlIHByb2plY3QsIHBsZWFzZSBjbGljayB0aGUgaW1hZ2UgYmVsb3cuIEl0IGNvbnRhaW5zIG90aGVyIGludGVyZXN0aW5nIHZpc3VhbGl6YXRpb25zIHRoYXQgYXJlIG5vdCBzaG93biBpbiB0aGlzIG5vdGVib29rLgpbIVtTaGlueV0oLi4vMDMgVmlzdWFsaXphdGlvbnMvc2hpbnkucG5nKV0oaHR0cHM6Ly9hbmRyZXdjaG91LnNoaW55YXBwcy5pby9maW5hbHByb2plY3QvKQoKCgoKCgo=